#include "log.hpp"
#include <iostream>
#include <cstdio>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <strings.h>
#include <queue>


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>


#define SIZE 1024

class UdpServer
{
public:
    UdpServer(uint16_t port, std::string ip = "") 
    : _port(port), 
    _ip(ip), 
    _sock(-1)
    {
        ;
    }
   
   void initServer()
   {
    //1.创建套接字
        _sock=socket(AF_INET,SOCK_DGRAM,0);//协议家族，服务类型(tcp是字节流，udp是数据报头)，协议类别(指明是tcp or udp，指明会自己默认自动识别)
        if(_sock<0)
        {
            logMessage(FATAL,"%d,%s",errno,strerror(errno));
            exit(2);
        }
    logMessage(NORMAL,"socket success ... sockfd:%d ,strerror:%s",_sock,strerror(errno));


    //2.绑定
    struct sockaddr_in local;//写入服务端信息
    bzero(&local,sizeof(local));//将local全部字节清0

    ////struct sockaddr_in  本质
    //{
    // unsigned short int sin_family;
    // unsigned short int sin_port;
    // unsigned int sin_ip;
    //}
    ////

    local.sin_family =AF_INET;
    //host to net by short.由 主机序列(unsigned short int) 转为 网络字节序 (unsigned short int)
    local.sin_port=htons(_port);
    //_ip若为空，则指定从任意ip上接收数据。若_ip不为空，则将ip由 主机序列(点分十进制的字符串(c语言风格))类型 转为 网络序列(unsigned int)
    local.sin_addr.s_addr=_ip.empty()?INADDR_ANY:inet_addr(_ip.c_str());

    if(bind(_sock,(struct sockaddr*)&local,sizeof local)<0)
    {
        logMessage(FATAL," %d %s ",errno,strerror(errno));//表示绑定失败，说明指定的ip和port 与 指定的套接字 绑定失败了
        exit(2);
    }
    logMessage(NORMAL,"bind success ... %s",strerror(errno));

    logMessage(NORMAL,"init udp server done ... %s",strerror(errno));

    //done 
    return ;

   }

   
     void Start()
    {
        char buffer[SIZE];//用于接收客户端发来的数据
        while(true)//永远不会退出，除非服务端挂了
        {
            sleep(1);
    //3.接收数据，并获取对端网络相关信息
            struct sockaddr_in peer;
            bzero(&peer, sizeof(peer));
            socklen_t len =sizeof(peer);
            
            ssize_t size=recvfrom(_sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);//获取服务端的网络信息
            if(size>0)
            {
                buffer[size]='\0';
                uint16_t port=ntohs(peer.sin_port);//16位unsgined short 转 unsigned short
                std::string ip=inet_ntoa(peer.sin_addr);//struct sock_in 转 char*(再构造string对象)
                std::cout<<ip<<":"<<"#"<<buffer<<std::endl;
            }
            else
            {
                std::cerr<<"recvfrom error"<<std::endl;
            }       

            std::string echo_msg="server get->: ";
            echo_msg+=buffer;
            sendto(_sock,echo_msg.c_str(),echo_msg.size(),0,(struct sockaddr*)&peer,len);
        }
    }
    ~UdpServer()
    {
        if (_sock >= 0)
            close(_sock);
    }

private:
    uint16_t _port;//端口号 unsigned short int 
    std::string _ip;//ip地址
    int _sock;//套接字
};
